package main

import (
	"errors"
	"fmt"
	"github.com/tealeg/xlsx"
	"math/rand"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"time"
)

const (
	Path = "05_党的二十大精神题库.xlsx"
)

var (
	OptionsMap = map[int]string{
		0: "A",
		1: "B",
		2: "C",
		3: "D",
		4: "E",
	}
	OptionsMap2 = map[string]int{
		"A": 0,
		"B": 1,
		"C": 2,
		"D": 3,
		"E": 4,
	}
	QuestionTypeMap = map[QuestionType]string{
		Single:   "单选题",
		Multiple: "多选题",
		Judge:    "判断题",
	}
)

type QuestionType int

const (
	Single QuestionType = iota
	Multiple
	Judge
)

type Question struct {
	No    int
	Title string
	// 备选答案
	Options []*Option
	Type    QuestionType
	Answer  string
}

type Option struct {
	Title  string
	Index  string
	IsTrue bool
}
type Answer struct {
	QuestionNo  int
	Answer      string
	RightAnswer string
}

func main() {

	// 打开Excel文件
	questions := Excel2Sys(Path)
	var (
		answers = []Answer{}
	)
	ShuffleQuestions(questions)
	questions = questions[:10]
	for i, _ := range questions {
		cmd := exec.Command("cmd", "/c", "cls")
		cmd.Stdout = os.Stdout
		cmd.Run()
		fmt.Printf("共%v题，当前是第%v题\n(%v-%v):%s\n", len(questions), i+1, QuestionTypeMap[questions[i].Type], questions[i].No, questions[i].Title)
		switch questions[i].Type {
		case Single:
			fallthrough
		case Multiple:
			for i2, _ := range questions[i].Options {
				fmt.Printf("%s: %s\t", OptionsMap[i2], questions[i].Options[i2].Title)
			}
		case Judge:
		}
		var answer string
		fmt.Print("\n请输入答案:")
		fmt.Scan(&answer)
		answer = strings.ToUpper(answer)
		// 错题收集
		if answer != questions[i].Answer {
			answers = append(answers, Answer{
				QuestionNo:  i,
				Answer:      answer,
				RightAnswer: questions[i].Answer,
			})
		}
		cmd = exec.Command("cmd", "/c", "cls")
		cmd.Stdout = os.Stdout
		cmd.Run()
	}
	for i, answer := range answers {
		fmt.Printf("\n(%v-%v):%s\n", QuestionTypeMap[questions[answer.QuestionNo].Type], questions[answer.QuestionNo].No, questions[answer.QuestionNo].Title)
		for i2, _ := range questions[i].Options {
			fmt.Printf("%s: %s\t", OptionsMap[i2], questions[answer.QuestionNo].Options[i2].Title)
		}
		fmt.Printf("\n你选了: %s\n", answer.Answer)
		fmt.Printf("正确答案: %s\n", answer.RightAnswer)
	}
}

// 读取
func Excel2Sys(patn string) []Question {
	var qs []Question
	file, err := xlsx.OpenFile(patn)
	if err != nil {
		fmt.Println("无法打开Excel文件:", err)
		return qs
	}
	qs = append(qs, CollectionQuestion(file.Sheets[0], Single)...)
	//qs = append(qs, CollectionQuestion(file.Sheets[1], Multiple)...)
	//qs = append(qs, CollectionQuestion(file.Sheets[2], Judge)...)
	return qs
}
func CollectionQuestion(sheet *xlsx.Sheet, questionType QuestionType) (questions []Question) {
	for _, row := range sheet.Rows {
		question, err := ReadQuestion(row, questionType)
		if err != nil {
			continue
		}
		questions = append(questions, question)
	}
	return
}

func ReadQuestion(row *xlsx.Row, questionType QuestionType) (Question, error) {
	// 备选变量
	var (
		options  []*Option
		answer   string
		question = Question{Type: questionType}
	)
	// 跳过无关行
	nu, err := strconv.Atoi(row.Cells[0].String())
	if err != nil {
		return Question{}, errors.New("读取题目序号错误")
	}
	question.No = nu
	// 读取题目
	question.Title = row.Cells[1].String()
	switch questionType {
	case Single:
		// 读取备选答案
		for i, cell := range row.Cells[2:] {
			option := Option{
				Title: cell.String(),
			}
			if i == 0 {
				option.IsTrue = true
			}
			options = append(options, &option)
		}
		Shuffle(options)
		for i, _ := range options {
			if options[i].IsTrue {
				question.Answer = options[i].Index
			}
		}
		question.Options = options
	case Multiple:
		// 读取备选答案
		answer = row.Cells[7].String()
		answerStr := strings.Split(answer, "") // AD
		//  记录多选正确答案序号
		rightAnswerMap := make(map[int]struct{}) // {0:struct{}{},3:struct{}{}}
		// 记录多选正确答案序号
		for i, _ := range answerStr {
			rightAnswerMap[OptionsMap2[answerStr[i]]] = struct{}{}
		}
		for i, cell := range row.Cells[2:7] {
			if strings.TrimSpace(cell.String()) == "" {
				break
			}
			option := Option{
				Title: cell.String(),
			}
			if _, ok := rightAnswerMap[i]; ok {
				option.IsTrue = true
			}
			options = append(options, &option)
		}
		Shuffle(options)
		for i, _ := range options {
			if options[i].IsTrue {
				question.Answer += options[i].Index
			}
		}
		question.Options = options
	case Judge:
		if strings.Contains(row.Cells[2].String(), `√`) {
			question.Answer = "A"
		} else {
			question.Answer = "B"
		}
	default:
		return Question{}, errors.New("不支持的类型")
	}
	return question, nil
}

// Shuffle 备选答案乱序
func Shuffle(options []*Option) {
	// 设置随机种子
	rand.Seed(time.Now().UnixNano())

	// 使用Fisher-Yates算法对结构体切片进行乱序
	for i := len(options) - 1; i >= 0; i-- {
		j := rand.Intn(i + 1)
		options[i], options[j] = options[j], options[i]
	}
	for i, _ := range options {
		options[i].Index = OptionsMap[i]
	}
	time.Sleep(time.Millisecond)
}

// Shuffle 备选答案乱序
func ShuffleQuestions(options []Question) {
	// 设置随机种子
	rand.Seed(time.Now().UnixNano())

	// 使用Fisher-Yates算法对结构体切片进行乱序
	for i := len(options) - 1; i >= 0; i-- {
		j := rand.Intn(i + 1)
		options[i], options[j] = options[j], options[i]
	}
	time.Sleep(time.Millisecond)
}
